﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Diagnostics.CodeAnalysis;

namespace Elentok.Common
{
  /// <summary>
  /// An XHTML writer
  /// </summary>
  public class XhtmlWriter : XmlTextWriter
  {
    private XhtmlDocType docType;

    /// <summary>
    /// Get the encoding used by the writer
    /// </summary>
    public Encoding Encoding { get; private set; }

    /// <summary>
    /// Initializes a new instance of the <see cref="XhtmlWriter"/> class
    /// </summary>
    /// <param name="stream"></param>
    /// <param name="encoding"></param>
    /// <param name="docType"></param>
    public XhtmlWriter(Stream stream, Encoding encoding, XhtmlDocType docType) : base(stream, encoding)
    {
      this.docType = docType;
      this.Encoding = encoding;
      this.Formatting = Formatting.Indented;
    }

    /// <summary>
    /// Writes:
    /// &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
    ///   &lt;head&gt;
    ///     &lt;meta http-equiv="Content-Type" content="text/html;charset=..." /&gt;
    /// </summary>
    public void WriteStartHeader()
    {
      WriteRaw(GetDocType(this.docType));
      WriteRaw("\n");

      WriteHtmlStartElement();
      WriteStartElement("head");
      WriteContentTypeMetadata();
    }

    /// <summary>
    /// Writes &lt;/head&gt;
    /// </summary>
    public void WriteEndHeader()
    {
      // close the "head" element
      WriteEndElement();
    }

    /// <summary>
    /// Writes &lt;style type="text/css"&gt; ... &lt;/style&gt;
    /// </summary>
    /// <param name="css"></param>
    public void WriteCss(string css)
    {
      WriteStartElement("style");
      WriteAttributeString("type", "text/css");
      WriteString(css);
      WriteEndElement();
    }

    /// <summary>
    /// Writes &lt;body&gt;
    /// </summary>
    public void WriteStartBody()
    {
      WriteStartElement("body");
    }

    /// <summary>
    /// Writes &lt;/body&gt;
    /// </summary>
    public void WriteEndBody()
    {
      WriteEndElement();
    }

    /// <summary>
    /// Writes:
    /// </summary>
    public void WriteFooter()
    {
      WriteEndElement();
    }

    /// <summary>
    /// Writes the &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt; tag
    /// </summary>
    public void WriteHtmlStartElement()
    {
      WriteStartElement("html");
      WriteAttributeString("xmlns", "http://www.w3.org/1999/xhtml");
      WriteAttributeString("xml:lang", "en");
      WriteAttributeString("lang", "en");
    }

    /// <summary>
    /// Writes the &lt;meta http-equiv="Content-Type" content="text/html;charset=..." /&gt; tag
    /// </summary>
    public void WriteContentTypeMetadata()
    {
      WriteStartElement("meta");
      WriteAttributeString("http-equiv", "Content-Type");
      WriteAttributeString("content", "text/html;charset=" + Encoding.WebName);
      WriteEndElement();
    }

    /// <summary>
    /// Writes &lt;link type="text/css" rel="stylesheet" href="..." /&gt;
    /// </summary>
    /// <param name="href"></param>
    public void WriteStyleSheetLink(string href)
    {
      WriteStartElement("link");
      WriteAttributeString("type", "text/css");
      WriteAttributeString("rel", "stylesheet");
      WriteAttributeString("href", href);
      WriteEndElement();
    }

    private static string GetDocType(XhtmlDocType docType)
    {
      switch (docType)
      {
        case XhtmlDocType.Xhtml10Strict:
          return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">";

        case XhtmlDocType.Xhtml10Transitional:
          return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";

        case XhtmlDocType.Xhtml10Frameset:
          return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">";

        case XhtmlDocType.Xhtml11:
          return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";
      }

      throw new ArgumentOutOfRangeException("docType");
    }
  }

  /// <summary>
  /// The type of document to generate
  /// </summary>
  public enum XhtmlDocType
  {
    /// <summary>
    /// XHTML 1.0 Strict
    /// </summary>
    Xhtml10Strict,
    
    /// <summary>
    /// XHTML 1.0 Transitional
    /// </summary>
    Xhtml10Transitional,
    
    /// <summary>
    /// XHTML 1.0 Frameset
    /// </summary>
    Xhtml10Frameset,

    /// <summary>
    /// XHTML 1.1
    /// </summary>
    Xhtml11
  }
}
